package com.eastdigit.bpm.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.eastdigit.bpm.cmd.TaskJumpActivitiCmd;
import com.eastdigit.bpm.util.BpmUtil;
import com.eastdigit.data.Constant;
import com.eastdigit.servlet.ReqBean;
import com.eastdigit.system.model.BusinessException;
import com.eastdigit.util.DateUtil;
import com.eastdigit.util.StringUtil;

/**
 * Created by Administrator on 2015/9/21.
 */
@Service
public class TasksService {

	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private FormService formService;
	@Autowired
	private TaskService taskService;
	@Autowired
	protected HistoryService historyService;
	@Autowired
	protected RuntimeService runtimeService;
	@Autowired
	private ProcessService processService;
	@Autowired
	private IdentityService identityService;
	@Autowired
    private ManagementService managementService;


	/**
	 * 待办列表
	 *
	 * @param reqBean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public JSONObject getTasks(ReqBean reqBean) {
		TaskQuery taskQuery = taskService.createTaskQuery();
		int pageSize = reqBean.getInfoInt(Constant.PAGE_SIZE);
        pageSize = pageSize <= 0 ? 10 : pageSize;
		int start = reqBean.getInfoInt(Constant.PAGE_INDEX) * pageSize;
		long count = 0;
		List<Task> list = new ArrayList<Task>();
		
		String processDefinitionKey = reqBean.getInfo("processDefinitionKey");
		if (!StringUtil.isEmpty(processDefinitionKey)) {
			taskQuery.processDefinitionKey(processDefinitionKey);
		}
		String taskDefinitionKey = reqBean.getInfo("taskDefinitionKey");
		if (!StringUtil.isEmpty(taskDefinitionKey)) {
			taskQuery.taskDefinitionKey(taskDefinitionKey);
		}
		String processInstanceId = reqBean.getInfo("processInstanceId");
		if (!StringUtil.isEmpty(processInstanceId)) {
			taskQuery.processInstanceId(processInstanceId);
		}
		String taskId = reqBean.getInfo("taskId");
		if (!StringUtil.isEmpty(taskId)) {
			taskQuery.taskId(taskId);
		}
		String createTimeAfter = reqBean.getInfo("createTimeAfter");
		if (!StringUtil.isEmpty(createTimeAfter)) {
			taskQuery.taskCreatedAfter(DateUtil.parseDateTime(createTimeAfter));
		}
		String createTimeBefore = reqBean.getInfo("createTimeBefore");
		if (!StringUtil.isEmpty(createTimeBefore)) {
			taskQuery.taskCreatedBefore(DateUtil.addDay(DateUtil.parse(createTimeBefore),1));
		}
		String active = reqBean.getInfo("active");
		if (!StringUtil.isEmpty(active)) {
			if (Boolean.valueOf(active)) {
				taskQuery.active();
			} else {
				taskQuery.suspended();
			}
		}
		String owner = reqBean.getInfo("owner");
		if (!StringUtil.isEmpty(owner)) {
			taskQuery.taskOwner(owner);
		}
		String unassigned = reqBean.getInfo("unassigned");
		if (!StringUtil.isEmpty(unassigned) && Boolean.valueOf(unassigned)) {//是否已分配
			taskQuery.taskUnassigned();
		}
		String assignee = reqBean.getInfo("assignee");
		if (!StringUtil.isEmpty(assignee)) {
			taskQuery.taskAssignee(assignee);
		}
		String candidateUser = reqBean.getInfo("candidateUser");
		if (!StringUtil.isEmpty(candidateUser)) {
			taskQuery.taskCandidateUser(candidateUser);
		}
		String candidateGroup = reqBean.getInfo("candidateGroup");
		if (!StringUtil.isEmpty(candidateGroup)) {
			taskQuery.taskCandidateGroup(candidateGroup);//与candidateGroupIn互斥
		}
		List<String> candidateGroups = (List<String>)reqBean.getInfoObj("candidateGroups");
		if (candidateGroups != null && !candidateGroups.isEmpty()) {
			taskQuery.taskCandidateGroupIn(candidateGroups);//与candidateGroup互斥
		}
		String candidateOrAssignedUserId = reqBean.getInfo("candidateOrAssignedUserId");
		if (!StringUtil.isEmpty(candidateOrAssignedUserId)) {
			taskQuery.taskCandidateOrAssigned(candidateOrAssignedUserId);//与candidateUser,candidateGroup互斥
		}
		taskQuery.orderByTaskCreateTime().desc();
		list = taskQuery.listPage(start, pageSize);
		count = taskQuery.count();

		JSONArray array = new JSONArray();
		for (Task task : list) {
			JSONObject j = BpmUtil.toJSONObject(task);
			
			ProcessDefinition processDefinition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
			j.put("processDefinition",BpmUtil.toJSONObject(processDefinition));
			
			HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
					.processInstanceId(task.getProcessInstanceId()).singleResult();
			j.put("processInstance",BpmUtil.toJSONObject(hpi));
			
			JSONObject form = new JSONObject();
			if(!StringUtil.isEmpty(hpi.getBusinessKey())){
				form = FormFactory.getFormData(hpi.getBusinessKey());
			}
			j.put("form", form);
			
			array.add(j);
		}
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("rows", array);
		jsonObject.put("total", count);

		return jsonObject;
	}
	
	/**
	 * 已办任务
	 *
	 * @param reqBean
	 * @return
	 */
	public JSONObject getHadDone(ReqBean reqBean) {
		HistoricTaskInstanceQuery htiQuery = historyService.createHistoricTaskInstanceQuery();
		String processDefinitionKey = reqBean.getInfo("processDefinitionKey");
		if (!StringUtil.isEmpty(processDefinitionKey)) {
			htiQuery.processDefinitionKey(processDefinitionKey);
		}
		String taskDefinitionKey = reqBean.getInfo("taskDefinitionKey");
		if (!StringUtil.isEmpty(taskDefinitionKey)) {
			htiQuery.taskDefinitionKey(taskDefinitionKey);
		}
		String processInstanceId = reqBean.getInfo("processInstanceId");
		if (!StringUtil.isEmpty(processInstanceId)) {
			htiQuery.processInstanceId(processInstanceId);
		}
		String taskId = reqBean.getInfo("taskId");
		if (!StringUtil.isEmpty(taskId)) {
			htiQuery.taskId(taskId);
		}
		
		String createTimeAfter = reqBean.getInfo("createTimeAfter");
		if (!StringUtil.isEmpty(createTimeAfter)) {
			htiQuery.taskCreatedAfter(DateUtil.parseDateTime(createTimeAfter));
		}
		String createTimeBefore = reqBean.getInfo("createTimeBefore");
		if (!StringUtil.isEmpty(createTimeBefore)) {
			htiQuery.taskCreatedBefore(DateUtil.addDay(DateUtil.parse(createTimeBefore),1));
		}
		
		if (reqBean.containsKey("assignee")) {
			htiQuery.taskAssignee(reqBean.getInfo("assignee"));
		}
		
		htiQuery.finished().orderByTaskCreateTime().desc();

		int pageSize = reqBean.getInfoInt(Constant.PAGE_SIZE);
        pageSize = pageSize <= 0 ? 10 : pageSize;
		int start = reqBean.getInfoInt(Constant.PAGE_INDEX) * pageSize;
		List<HistoricTaskInstance> list = htiQuery.listPage(start, pageSize);
		JSONArray array = new JSONArray();
		for (HistoricTaskInstance task : list) {
			JSONObject j = BpmUtil.toJSONObject(task);
			
			ProcessDefinition processDefinition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
			j.put("processDefinition",BpmUtil.toJSONObject(processDefinition));
			
			HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
					.processInstanceId(task.getProcessInstanceId()).singleResult();
			j.put("processInstance",BpmUtil.toJSONObject(hpi));
			
			JSONObject form = new JSONObject();
			if(!StringUtil.isEmpty(hpi.getBusinessKey())){
				form = FormFactory.getFormData(hpi.getBusinessKey());
			}
			j.put("form", form);
			
			array.add(j);
		}
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("rows", array);
		jsonObject.put("total", htiQuery.count());

		return jsonObject;

	}

	/**
	 * 获取任务表单相关数据
	 *
	 * @param taskId
	 * @return
	 * @throws Exception
	 */
	public JSONObject getTaskForm(String taskId) {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
		TaskFormData taskFormData = formService.getTaskFormData(taskId);
		JSONObject taskForm = FormFactory.getForm(taskFormData);
		if (!taskForm.containsKey("key") || StringUtil.isEmpty(taskForm.getString("key"))) {
			JSONObject startForm = FormFactory.getForm(formService.getStartFormData(task.getProcessDefinitionId()));
			if (startForm.containsKey("key")) {
				taskForm.put("key", startForm.getString("key"));
			}
		}
		taskForm.put("task", BpmUtil.toJSONObject(task));
		taskForm.put("form", FormFactory.getFormData(processInstance.getBusinessKey()));
		taskForm.put("comments", processService.getProcessComments(task.getProcessInstanceId()));
		taskForm.put("buttons", getTaskActions(taskId));
		
		ProcessDefinition processDefinition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
		taskForm.put("processDefinitionKey", processDefinition.getKey());
		taskForm.put("processDefinition", BpmUtil.toJSONObject(processDefinition));

		return taskForm;
	}



	/**
	 * 获取任务下一步按钮
	 *
	 * @param taskId
	 * @return
	 */
	public JSONArray getTaskActions(String taskId) {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		String activitiId = execution.getActivityId();
		ProcessDefinitionEntity pd = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(task
				.getProcessDefinitionId());
		ActivityImpl activity = pd.findActivity(activitiId);
		JSONArray list = new JSONArray();
		for (PvmTransition outgoingTransition : activity.getOutgoingTransitions()) {
			JSONObject action = new JSONObject();
			String transName = (String) outgoingTransition.getProperty("name");
			action.put("id", outgoingTransition.getId());
			action.put("name", StringUtil.noNull(transName, "提交"));
			list.add(action);
		}
		return list;
	}

	/**
	 * 任务推进
	 *
	 * @param taskId
	 * @param properties
	 */
	public void complete(String taskId, String properties, String currentUserId) throws Exception {
		try {
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			if(StringUtil.isEmpty(task.getAssignee())){
			    taskService.unclaim(taskId);
				task.setAssignee(currentUserId);
				taskService.claim(taskId, currentUserId);
			}
	    	identityService.setAuthenticatedUserId(task.getAssignee());
			
			//保存业务数据
			Map<String, String> map = FormFactory.getProperties(properties);
			map.put("processInstanceId", task.getProcessInstanceId());
			FormFactory.getFormService(map).update(map);
			
			// 设置当前流程需要的流程变量
			Map<String, Object> variables = new HashMap<String, Object>();
	        variables.putAll(map);
	        
	        //保存comment
	        Iterator<Map.Entry<String,Object>> it = variables.entrySet().iterator();
	        while(it.hasNext()){
	        	Map.Entry<String,Object> entry = it.next();
	        	String variableName = entry.getKey();
	        	if (variableName.startsWith("comment_")) {
					taskService.addComment(taskId, task.getProcessInstanceId(), variableName, (String)variables.get(variableName));
				}
	        }
	        
			taskService.complete(taskId, variables);
		 }catch(Exception e){
			 throw new BusinessException(e.getMessage());
		 }finally{
			 identityService.setAuthenticatedUserId(null);
		 }
	}
	

	/**
	 * 审批意见
	 *
	 * @param taskId
	 * @return
	 */
	public JSONArray getComments(String taskId) {
		JSONArray jsonArray = new JSONArray();
		List<Comment> comments = new ArrayList<Comment>();
		if (!StringUtil.isEmpty(taskId)) {
				comments = taskService.getTaskComments(taskId);
				for (Comment comm : comments) {
					JSONObject json = new JSONObject();
					json.put("taskId", comm.getTaskId());
					json.put("processInstanceId", comm.getProcessInstanceId());
					json.put("commentTime", DateUtil.formatDateTime(comm.getTime()));
					json.put("message", comm.getFullMessage());
					json.put("type", comm.getType());
					json.put("userId",StringUtil.noNull(comm.getUserId(),""));
					jsonArray.add(json);
				}
		}
		return jsonArray;
	}

	/**
	 * 签收任务
	 *
	 * @param taskId
	 * @return
	 */
	public void claimTask(String taskId, String userId) {
		taskService.claim(taskId, userId);
	}
	
	/**
     * 可退回任务环节
     *
     * @param taskId
     * @return
     */
    public JSONArray getBackableActs(String taskId) {
        
        JSONArray jsonArray = new JSONArray();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        List<HistoricActivityInstance> actList = historyService.createHistoricActivityInstanceQuery().executionId(task.getExecutionId()).processDefinitionId(
				task.getProcessDefinitionId()).activityType("userTask").list();
		Map<String,HistoricActivityInstance> map = new HashMap<String, HistoricActivityInstance>();
        if(actList.size() > 0) {
            for (HistoricActivityInstance act : actList) {
                if(task.getTaskDefinitionKey().equals(act.getActivityId())){
                    continue;
                }
				map.put(act.getActivityId(), act);
            }
        }
		for(Map.Entry<String, HistoricActivityInstance> entry : map.entrySet()) {
			JSONObject json = new JSONObject();
			json.put("activityId", entry.getKey());
			json.put("taskId",entry.getValue().getTaskId());
			json.put("actName",entry.getValue().getActivityName());
			jsonArray.add(json);
		}
        return jsonArray;
    }
    
    public void toBackTask (ReqBean reqBean) {
        String taskId = reqBean.getInfo("taskId");
        String actId = reqBean.getInfo("actId");
        Assert.notNull(taskId, "缺少参数taskId!");
        Assert.notNull(actId, "缺少参数actId!");
        try {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if(StringUtil.isEmpty(task.getAssignee())){
                taskService.unclaim(taskId);
                task.setAssignee(reqBean.getUserId());
                taskService.claim(taskId, reqBean.getUserId());
            }
            identityService.setAuthenticatedUserId(task.getAssignee());
            managementService.executeCommand(new TaskJumpActivitiCmd(taskId, actId, null));
        }catch(Exception e){
            throw new BusinessException(e.getMessage());
        }finally{
            identityService.setAuthenticatedUserId(null);
        }
    }

}
